package design_pattern.producer_and_consumer;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @ClassName : design_pattern.producer_and_consumer.myBlockingQueue
 * @Description : ReentrantLock 解决虚假唤醒
 * Created by cyd on 2021-10-14 11:32:31
 */
public class MyBlockingQueue<E> {
    private Queue<E> queue;
    private final int capacity;

    private final ReentrantLock lock = new ReentrantLock();
    // 两个阻塞线程等待锁信号
    private final Condition full = lock.newCondition();
    private final Condition empty = lock.newCondition();

    public synchronized int getNum() {
        return queue.size();
    }

    public MyBlockingQueue() {
        capacity = 16;
    }

    public MyBlockingQueue(int capacity) {
        queue = new LinkedList<>();
        this.capacity = capacity;
    }

    public void put(E e) throws InterruptedException {
        lock.lockInterruptibly();
        try {
            while (queue.size() >= capacity) {
                // 发现是满的，进去full锁的等待池等待
                full.await();
            }
            if (queue.size() == 0) {
                // 发出队列已空的信号，通知empty锁住的线程（取的）来放
                empty.signal();
            }
            System.out.println("放入前queue的size：" + queue.size());
            queue.add(e);
        } finally {
            lock.unlock();
        }
    }

    public E take() throws InterruptedException {
        lock.lockInterruptibly();
        try {
            while (queue.size() == 0) {
                // 发现是空的，进去empty锁的等待池等待
                empty.await();
            }
            if (queue.size() >= capacity) {
                // 发出队列已经满的信号，通知full锁住的线程（放的）来取
                full.signal();
            }
            return queue.remove();
        } finally {
            lock.unlock();
        }
    }
}